#include "fileTransfer.h"

int downloadHandle(int sockfd)
{
    // 定义小火车
    train_t train;

    // 接收文件名
    char filename[4096];
    recv(sockfd, &train.length, sizeof(train.length), MSG_WAITALL); // 接收文件名长度
    recv(sockfd, &train.data, train.length, MSG_WAITALL);           // 接收文件名内容
    memcpy(filename, train.data, train.length);
    filename[train.length] = '\0';

    // 打开文件
    int fd = open(filename, O_RDONLY);

    // 发送文件长度
    struct stat statbuf;
    fstat(fd, &statbuf);
    off_t filesize = statbuf.st_size; // 可以直接发

    train.length = sizeof(filesize);
    memcpy(train.data, &filesize, train.length);
    send(sockfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);

    // 传输文件
    if (filesize > big_file_size) // 大文件：mmap 实现零拷贝
    {
        ftruncate(fd, filesize);

        // 建立映射区
        char *p = (char *)mmap(NULL, filesize,
                               PROT_READ, MAP_SHARED, fd, 0); // 权限和open一致

        off_t offset = 0; // 偏移量
        while (1)
        {
            if (offset >= filesize) // 跳出循环条件
            {
                break;
            }
            if (filesize - offset > 1000) // 未传输数据量
            {
                train.length = 1000;
            }
            else // 最后一次传输
            {
                train.length = filesize - offset;
            }

            send(sockfd, &train.length, sizeof(train.length), MSG_NOSIGNAL);
            send(sockfd, p + offset, train.length, MSG_NOSIGNAL); // 从内核态到内核态
            offset += train.length;
        }

        train.length = 0;
        send(sockfd, &train.length, sizeof(train.length), MSG_NOSIGNAL); // 发一个空车厢

        // 释放映射区
        munmap(p, filesize);
    }
    else // 小文件
    {
        while (1)
        {
            bzero(train.data, sizeof(train.data));                       // 清空车厢
            ssize_t ret_read = read(fd, train.data, sizeof(train.data)); // 将文件内容读取到火车厢
            train.length = ret_read;                                     // 设置火车头
            send(sockfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
            if (ret_read == 0) // 最后一次read已经没有数据了，ret=0，此时是一个空车厢
            {
                break;
            }
        }
    }

    close(fd);
    return 0;
}
